package food;

import impsoft.bots.reflection.Interface;
import impsoft.scripting.ibot.enums.InventorySlot;
import impsoft.scripting.ibot.enums.Skill;
import impsoft.scripting.ibot.itemrec.ItemCondition;
import impsoft.scripting.ibot.itemrec.ItemContains;
import impsoft.scripting.ibot.itemrec.ItemContainsIgnore;
import impsoft.scripting.ibot.itemrec.ItemRegex;
import impsoft.utils.general.Timer;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import base.DreamScript;
import bergCoder.ItemEquals;
import conditions.ItemEqualsAny;

public class FoodManager {
	private String preferred = "";
	private DreamScript cs;
	public static String[] GUTHANS = new String[] { "Guthan's platebody", "Guthan's warspear", "Guthan's helm",
			"Guthan's chainskirt" };
	public static ItemCondition BONES = new ItemContainsIgnore("bones", new String[] { "bones to peaches",
			"Bones to peaches", "Bones to Peaches", "Bones To Peaches", "Peach" });
	public static ItemCondition BONES_TO_PEACHES = new ItemContains("Bones to peaches");
	public static ItemCondition PEACH = new ItemEquals("Peach");

	public FoodManager(DreamScript ds) {
		cs = ds;
	}

	public void setPreferredFood(String foodName) {
		preferred = foodName;
	}

	public String getPreferredFood() {
		return preferred;
	}

	/*
	 * @return all existing food types as a string array.
	 */
	public static FoodItem[] getAllFoodTypes() {
		return FoodItem.values();
	}

	public FoodPiece[] getAllFoodPieces() {
		ArrayList<FoodPiece> pieceList = new ArrayList<FoodPiece>();

		for (FoodItem fi : FoodItem.values()) {
			for (FoodPiece piece : fi.getPieces()) {
				pieceList.add(piece);
			}
		}

		return pieceList.toArray(new FoodPiece[pieceList.size()]);
	}

	/*
	 * @return Gets all food names reversed as a String[]
	 */
	public String[] getFoodNamesReversed() {
		FoodPiece[] array = getAllFoodPieces();
		String[] names = new String[array.length + 1];
		for (int i = 0; i < array.length - 1; i++) {
			names[i] = array[array.length - i - 1].getName();
		}

		return names;
	}

	public String[] getWholeFoodNames() {
		ArrayList<String> foodList = new ArrayList<String>();

		foodList.add("No food");
		for (FoodItem fi : FoodItem.values()) {
			foodList.add(fi.getName());
		}

		return foodList.toArray(new String[foodList.size()]);
	}

	public String[] getFoodPieceNames(FoodItem fi) {
		ArrayList<String> foodList = new ArrayList<String>();

		for (FoodPiece fp : fi.getPieces()) {
			foodList.add(fp.getName());
		}

		return foodList.toArray(new String[foodList.size()]);
	}

	public FoodPiece getFoodPiece(String name) {
		for (FoodPiece piece : getAllFoodPieces()) {
			if (piece.getName().equalsIgnoreCase(name)) {
				return piece;
			}
		}

		cs.log("FoodItem not found, please enter an exact name.");
		return null;
	}

	public FoodPiece[] getFoodPieces(String name) {
		List<FoodPiece> pieces = new ArrayList<FoodPiece>();
		for (FoodPiece piece : getAllFoodPieces()) {
			if (piece.getName().equalsIgnoreCase(name)) {
				pieces.add(piece);
			}
		}

		return pieces.toArray(new FoodPiece[pieces.size()]);
	}

	public FoodItem getFoodItem(String name) {
		for (FoodItem piece : FoodItem.values()) {
			if (piece.getName().equalsIgnoreCase(name)) {
				return piece;
			}
		}

		cs.log("FoodItem not found, please enter an exact name.");
		return null;
	}

	public int countNotedFood() throws InterruptedException {
		int i = 0;

		for (InventorySlot slot : InventorySlot.values()) {
			if (isFood(cs.theTabs.Inventory2.getName(slot)) && cs.theTabs.Inventory2.isANotedItem(slot)) {
				i++;
			}
		}

		return i;
	}

	public int countFood() throws InterruptedException {
		int i = 0;

		for (InventorySlot slot : InventorySlot.values()) {
			if (isFood(cs.theTabs.Inventory2.getName(slot))) {
				i++;
			}
		}

		return i;
	}

	/*
	 * @param Name of item to check @return Returns whether the item matches a
	 * valid FoodItem
	 */
	public boolean isFood(String itemName) {
		if (itemName == null) {
			return false;
		}

		for (FoodPiece piece : getAllFoodPieces()) {
			if (itemName.equalsIgnoreCase(piece.getName())) {
				return true;
			}
		}

		return false;
	}

	/*
	 * @return Returns how much the food in your inventory can heal together
	 */
	public int getTotalFoodHeal() throws InterruptedException {
		int healpower = 0;
		for (InventorySlot slot : InventorySlot.values()) {
			String itemName = null;
			if (isFood(itemName = cs.theTabs.Inventory2.getName(slot))) {
				healpower += getFoodPiece(itemName).getHeal();
			}
		}

		return healpower;
	}

	/*
	 * @return Returns percentage of full health.
	 */
	public int getHpPercentage() throws InterruptedException {
		int hp = getHealthPoints();
		int lvl = cs.theTabs.Statistics.getStatBottom(Skill.HITPOINTS);
		return lvl > 0 && hp > 0 ? (int) ((double) 100 * hp / (lvl * 10)) : 100;
	}

	public int getHealthPoints() throws InterruptedException {
		Interface i = cs.getInterfaceAtIndex(748, 8);
		if (i != null && i.isValid()) {
			String s = i.getText();
			if (s != null) {
				return Integer.parseInt(s);
			}
		}
		return cs.theTabs.Statistics.getStatBottom(Skill.HITPOINTS) * 10;
	}

	/*
	 * @return boolean if we have food or not.
	 */
	public boolean hasFood() throws InterruptedException {
		for (FoodItem food_type : getAllFoodTypes()) {
			if (cs.theTabs.Inventory.count(new ItemEqualsAny(food_type.getName())) > 0) {
				return true;
			}
		}

		for (FoodPiece food_piece : getAllFoodPieces()) {
			if (cs.theTabs.Inventory.count(new ItemEqualsAny(food_piece.getName())) > 0) {
				return true;
			}
		}

		return false;
	}

	public boolean heal(int hp) throws InterruptedException {
		if (hp < 90) {
			hp += cs.random(10);
		}

		while (hasFood() && getHpPercentage() < hp) {
			int percent = getHpPercentage();
			if (!heal()) {
				return false;
			}

			for (Timer t = new Timer(2000); t.isNotUp() && getHpPercentage() == percent;) {
				cs.sleep(100);
			}
		}

		return getHpPercentage() >= hp;
	}

	/*
	 * Will use any food we have in inventory to heal up.
	 */
	public boolean heal() throws InterruptedException {
		cs.getTabHandler().setTab(cs.theTabs.Inventory2);

		if (!hasFood()) {
			return false;
		} else if (!preferred.equals("") && isFood(preferred)) {
			ItemEqualsAny foodC = new ItemEqualsAny(getFoodPieceNames(getFoodItem(preferred)));

			if (cs.theTabs.Inventory.count(foodC) > 0) {
				cs.log("Eating " + preferred + " @" + cs.theMiniMapIndicators.getHealthPoints() + "LP");
				cs.getInventoryUtils().doInventory(foodC, "Eat", true);
				return true;
			}
		}

		if (hasFood()) {
			for (String foodName : getWholeFoodNames()) {
				if (!foodName.equalsIgnoreCase("No food")) {
					ItemEqualsAny foodC = new ItemEqualsAny(getFoodPieceNames(getFoodItem(foodName)));

					if (cs.theTabs.Inventory.count(foodC) > 0) {
						cs.log("Eating " + foodName + " @" + cs.theMiniMapIndicators.getHealthPoints() + "LP");
						cs.getInventoryUtils().doInventory(foodC, "Eat", true);
						return true;
					}
				}
			}
		}

		return false;
	}

	public ItemCondition edible = getEqualConditions(getFoodNamesReversed());
	{
		edible.stackSize = ItemCondition.STACK_SIZE_ONE;
	}

	public ItemCondition noted = getEqualConditions(getFoodNamesReversed());
	{
		noted.stackSize = ItemCondition.STACK_SIZE_GRATER_THAN_ONE;
	}

	private String getRegex(String ss[]) {
		String regex = "";
		for (String s : ss) {
			regex += s + "|";
		}

		if (regex.length() > 0) {
			regex = regex.substring(0, regex.length() - 1);
		}
		return regex;
	}

	private ItemCondition getConditions(String ss[]) {
		return new ItemRegex(Pattern.compile(getRegex(ss), Pattern.CASE_INSENSITIVE));
	}

	private ItemCondition getEqualConditions(String ss[]) {
		return new ItemEqualsAny(ss);
	}
}